WebAssembly Component Model
from WebAssembly
https://github.com/WebAssembly/component-model
https://component-model.bytecodealliance.org/
概要
WASM の相互運用可能性を高めるための仕様
WebAssembly Module で発生した以下のような問題を解消するための仕様
データ表現
関数呼び出し規約
メモリ管理
例外処理
開発体験
内部では、以下の 3 つの仕様を取りまとめている
Application Binary Interface(ABI)
インタフェース記述言語(IDL)
バイナリフォーマット
2024 年 10 月現在 Phase 1(Feature Proposal)ではあるが既に多くのツールが開発されており、広く受け入れられている
e.g.
Rust で書かれたソースコードを WebAssembly Component としてビルドするツール: cargo-component
WebAssembly Component を実行する クレート / CLI ツール: Wasmtime
WASI Preview 2 も、このコンポーネントモデルのインタフェースに従って実現される
なぜ Component Model が登場したか
WebAssembly Component Model 以前の仕様(WebAssembly Module)では、構造を持つデータのデータ表現をしていない
そのため、関数を呼び出す側と呼び出される側の両方が一定のルールに従う必要があった
具体例
以下のような Rust のコードを WASM としてビルドし、JavaScript から呼び出すことを考える
code:rs
struct A {
x: u32,
y: u8,
z: u16,
}
pub fn get_x(value: &A) -> u32 { value.x }
pub fn get_y(value: &A) -> u8 { value.y }
pub fn get_z(value: &A) -> u16 { value.z }
この場合、以下のように呼び出せることを期待するが、これは実行できない
code:js
const a = { x: 1, y: 2, z: 3 };
const x = instance.exports.get_x(a);
理由: WebAssembly Instance はサンドボックスで実行されており、a の値が保存されているメモリに get_x はアクセスできない ため
解決策
WebAssembly Instance が利用している線形メモリにオブジェクトをコピーする必要がある
code:rs
const a = { x: 1, y: 2, z: 3 };
// 線形メモリを u8 の配列として JavaScript から操作する
const memory = new UInt8Array(instance.exports.memory.buffer);
// x の値のコピー
memory0 = a.x & 0x03;
memory1 = a.x & 0x0c;
memory2 = a.x & 0x30;
memory3 = a.x & 0xc0;
// y の値のコピー
memory4 = a.y;
// z の値のコピー
memory5 = a.z & 0x03;
memory6 = a.z & 0x0c;
// コピーしたオブジェクトの先頭の添字を引数に関数を呼び出す
const x = instance.exports.get_x(0);
問題点
上記では、A オブジェクトは以下のようなルールで表現されていることを前提としている
x、y、z の順で属性値がメモリ上に並んで保存されること
バイトオーダは リトルエンディアン であること
属性値以外のデータはメモリ上に保存されないこと
関数を呼び出す側と呼び出される側の両方がこのルールに従う必要がある
しかし、この ルールが必ず守られるという保証は無い
そのため、コンパイラやビルド時の設定によっては、属性値が異なる順序で並んでいるケースもある
e.g. x、z、y
この場合、以下のように C と同じようにメモリ上に表現するよう指定する必要がある
code:rs
#repr(C)
struct A {
x: u32,
y: u8,
z: u16,
}
https://doc.rust-jp.rs/rust-nomicon-ja/other-reprs.html#reprc
上記のような問題点は、WASM のユースケースが単純であったり、小規模の場合は問題なかった
WASM の作成者と利用者の間でコミュニケーションによって合意を取る
WASM ファイルを作成するプログラミング言語やツールが少数であれば、使っているツールに合わせれば良い
上記のような問題点
データ表現以外にも以下のような問題もあった
関数呼び出し規約
メモリ管理
例外処理
開発体験
しかし、 WASM が登場して時間が経つにつれ、WASM が利用されるプロジェクトが巨大・複雑化すると問題が顕在化してきた
WASM が利用されるプロジェクトが巨大・複雑化
複数の WASM ファイルの利用
ある WebAssembly Module がエクスポートする関数を、別の WebAssembly Module にインポートする
WASM をビルドターゲットとして指定できるビルドツールも増えてきた
Component Model は上記の 5 つの問題すべてを解決するために策定された
参考
Rustで学ぶWebAssembly ―入門からコンポーネントモデルによる開発まで
https://zenn.dev/mierune/articles/2ea6dc72a7dd58
https://qiita.com/sachaos/items/e3a613b018febb898fde#component-model
#WebAssembly